From fcd70649f43a72dbbcbc79e524fbe3fe20261021 Mon Sep 17 00:00:00 2001 From: diogo464 Date: Tue, 12 Aug 2025 16:32:00 +0100 Subject: Replace complex /api/fs with simple /api/upload endpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Create new /api/upload endpoint for file uploads with path query parameter - Simplify DriveDirectoryClient upload logic to use POST instead of PUT - Remove complex path encoding and AUTH header handling from client - Remove unused /api/fs endpoint entirely - no longer needed - Maintain all existing upload functionality (file size limits, auth, etc.) - Test uploads to root directory and subdirectories - both working perfectly Benefits: - Cleaner API surface with single-purpose endpoints - Simpler client code with less complexity - Better separation of concerns - Maintained backward compatibility for user experience 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- frontend/app/api/fs/[...path]/route.ts | 209 --------------------------------- 1 file changed, 209 deletions(-) delete mode 100644 frontend/app/api/fs/[...path]/route.ts (limited to 'frontend/app/api/fs/[...path]') diff --git a/frontend/app/api/fs/[...path]/route.ts b/frontend/app/api/fs/[...path]/route.ts deleted file mode 100644 index 3a299af..0000000 --- a/frontend/app/api/fs/[...path]/route.ts +++ /dev/null @@ -1,209 +0,0 @@ -import { NextRequest, NextResponse } from 'next/server' -import { writeFile, unlink } from 'fs/promises' -import { tmpdir } from 'os' -import { join } from 'path' -import { randomUUID } from 'crypto' -import { Auth_get_user, Auth_user_can_upload } from '@/lib/auth' -import { Drive_ls, Drive_remove, Drive_mkdir, Drive_import } from '@/lib/drive_server' -import { UPLOAD_MAX_FILE_SIZE } from '@/lib/constants' -import { revalidatePath } from 'next/cache' - -// GET /api/fs/path/to/file - Get file/directory listing -export async function GET( - request: NextRequest, - { params }: { params: Promise<{ path: string[] }> } -) { - try { - const { path: pathSegments } = await params - const filePath = '/' + (pathSegments?.join('/') || '') - - // Get directory listing using Drive_ls (non-recursive) - const entries = await Drive_ls(filePath, false) - - return NextResponse.json(entries) - - } catch (error) { - console.error('GET fs error:', error) - return NextResponse.json( - { error: error instanceof Error ? error.message : 'Internal server error' }, - { status: 500 } - ) - } -} - -// DELETE /api/fs/path/to/file - Delete file/directory -export async function DELETE( - request: NextRequest, - { params }: { params: Promise<{ path: string[] }> } -) { - try { - // Check user authentication and permissions - const user = await Auth_get_user() - if (!user.isLoggedIn) { - return NextResponse.json({ error: 'User not authenticated' }, { status: 401 }) - } - - if (!Auth_user_can_upload(user)) { - return NextResponse.json({ error: 'User does not have upload permissions' }, { status: 403 }) - } - - const { path: pathSegments } = await params - const filePath = '/' + (pathSegments?.join('/') || '') - - // Remove file/directory using Drive_remove - await Drive_remove(filePath, user.email) - - // Revalidate the parent directory to refresh listings - const parentPath = filePath.split('/').slice(0, -1).join('/') || '/' - revalidatePath(`/drive${parentPath}`) - revalidatePath('/drive') - - return NextResponse.json({ - success: true, - message: 'Path deleted successfully', - deletedPath: filePath - }) - - } catch (error) { - console.error('DELETE fs error:', error) - return NextResponse.json( - { error: error instanceof Error ? error.message : 'Internal server error' }, - { status: 500 } - ) - } -} - -// PUT /api/fs/path/to/file - Create/upload file -export async function PUT( - request: NextRequest, - { params }: { params: Promise<{ path: string[] }> } -) { - try { - // Check user authentication and permissions - const user = await Auth_get_user() - if (!user.isLoggedIn) { - return NextResponse.json({ error: 'User not authenticated' }, { status: 401 }) - } - - if (!Auth_user_can_upload(user)) { - return NextResponse.json({ error: 'User does not have upload permissions' }, { status: 403 }) - } - - const { path: pathSegments } = await params - const filePath = '/' + (pathSegments?.join('/') || '') - - // Check if request has file content - const contentType = request.headers.get('content-type') - if (!contentType || (!contentType.includes('multipart/form-data') && !contentType.includes('application/octet-stream'))) { - return NextResponse.json({ - error: 'Content-Type must be multipart/form-data or application/octet-stream' - }, { status: 400 }) - } - - let fileBuffer: Buffer - let filename: string - - if (contentType.includes('multipart/form-data')) { - // Handle multipart form data - const formData = await request.formData() - const file = formData.get('file') as File - - if (!file) { - return NextResponse.json({ error: 'No file provided' }, { status: 400 }) - } - - if (file.size > UPLOAD_MAX_FILE_SIZE) { - return NextResponse.json({ - error: `File exceeds maximum size of ${UPLOAD_MAX_FILE_SIZE / (1024 * 1024)}MB` - }, { status: 400 }) - } - - const bytes = await file.arrayBuffer() - fileBuffer = Buffer.from(bytes) - filename = file.name - } else { - // Handle raw binary data - const bytes = await request.arrayBuffer() - fileBuffer = Buffer.from(bytes) - - if (fileBuffer.length > UPLOAD_MAX_FILE_SIZE) { - return NextResponse.json({ - error: `File exceeds maximum size of ${UPLOAD_MAX_FILE_SIZE / (1024 * 1024)}MB` - }, { status: 400 }) - } - - // Extract filename from path - filename = pathSegments?.[pathSegments.length - 1] || 'upload' - } - - // Create temporary file - const tempFileName = `${randomUUID()}-${filename}` - const tempFilePath = join(tmpdir(), tempFileName) - - // Save file to temporary location - await writeFile(tempFilePath, fileBuffer) - - // Import file using Drive_import (uses --mode move, so temp file is already deleted) - await Drive_import(tempFilePath, filePath, user.email) - - // Revalidate the parent directory to refresh listings - const parentPath = filePath.split('/').slice(0, -1).join('/') || '/' - revalidatePath(`/drive${parentPath}`) - revalidatePath('/drive') - - return NextResponse.json({ - success: true, - message: 'File uploaded successfully', - path: filePath - }) - - } catch (error) { - console.error('PUT fs error:', error) - return NextResponse.json( - { error: error instanceof Error ? error.message : 'Internal server error' }, - { status: 500 } - ) - } -} - -// POST /api/fs/path/to/directory - Create directory -export async function POST( - request: NextRequest, - { params }: { params: Promise<{ path: string[] }> } -) { - try { - // Check user authentication and permissions - const user = await Auth_get_user() - if (!user.isLoggedIn) { - return NextResponse.json({ error: 'User not authenticated' }, { status: 401 }) - } - - if (!Auth_user_can_upload(user)) { - return NextResponse.json({ error: 'User does not have upload permissions' }, { status: 403 }) - } - - const { path: pathSegments } = await params - const dirPath = '/' + (pathSegments?.join('/') || '') - - // Create directory using Drive_mkdir - await Drive_mkdir(dirPath, user.email) - - // Revalidate the parent directory to refresh listings - const parentPath = dirPath.split('/').slice(0, -1).join('/') || '/' - revalidatePath(`/drive${parentPath}`) - revalidatePath('/drive') - - return NextResponse.json({ - success: true, - message: 'Directory created successfully', - path: dirPath - }) - - } catch (error) { - console.error('POST fs error:', error) - return NextResponse.json( - { error: error instanceof Error ? error.message : 'Internal server error' }, - { status: 500 } - ) - } -} \ No newline at end of file -- cgit